﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameViewer.Core.Archives;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using GameViewer.Core;

namespace GameViewer.Ogre
{

    enum MeshChunkID
    {
        M_HEADER = 0x1000,
        // char*          version           : Version number check
        M_MESH = 0x3000,
        // bool skeletallyAnimated   // important flag which affects h/w buffer policies
        // Optional M_GEOMETRY chunk
        M_SUBMESH = 0x4000,
        // char* materialName
        // bool useSharedVertices
        // uint indexCount
        // bool indexes32Bit
        // uint* faceVertexIndices (indexCount)
        // OR
        // ushort* faceVertexIndices (indexCount)
        // M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
        M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing
        // ushort operationType
        M_SUBMESH_BONE_ASSIGNMENT = 0x4100,
        // Optional bone weights (repeating section)
        // uint vertexIndex;
        // ushort boneIndex;
        // float weight;
        // Optional chunk that matches a texture name to an alias
        // a texture alias is sent to the submesh material to use this texture name
        // instead of the one in the texture unit with a matching alias name
        M_SUBMESH_TEXTURE_ALIAS = 0x4200, // Repeating section
        // char* aliasName;
        // char* textureName;

        M_GEOMETRY = 0x5000, // NB this chunk is embedded within M_MESH and M_SUBMESH
        // uint vertexCount
        M_GEOMETRY_VERTEX_DECLARATION = 0x5100,
        M_GEOMETRY_VERTEX_ELEMENT = 0x5110, // Repeating section
        // ushort source;  	// buffer bind source
        // ushort type;    	// VertexElementType
        // ushort semantic; // VertexElementSemantic
        // ushort offset;	// start offset in buffer in bytes
        // ushort index;	// index of the semantic (for colours and texture coords)
        M_GEOMETRY_VERTEX_BUFFER = 0x5200, // Repeating section
        // ushort bindIndex;	// Index to bind this buffer to
        // ushort vertexSize;	// Per-vertex size, must agree with declaration at this index
        M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210,
        // raw buffer data
        M_MESH_SKELETON_LINK = 0x6000,
        // Optional link to skeleton
        // char* skeletonName           : name of .skeleton to use
        M_MESH_BONE_ASSIGNMENT = 0x7000,
        // Optional bone weights (repeating section)
        // uint vertexIndex;
        // ushort boneIndex;
        // float weight;
        M_MESH_LOD = 0x8000,
        // Optional LOD information
        // string strategyName;
        // ushort numLevels;
        // bool manual;  (true for manual alternate meshes, false for generated)
        M_MESH_LOD_USAGE = 0x8100,
        // Repeating section, ordered in increasing depth
        // NB LOD 0 (full detail from 0 depth) is omitted
        // LOD value - this is a distance, a pixel count etc, based on strategy
        // float lodValue;
        M_MESH_LOD_MANUAL = 0x8110,
        // Required if M_MESH_LOD section manual = true
        // String manualMeshName;
        M_MESH_LOD_GENERATED = 0x8120,
        // Required if M_MESH_LOD section manual = false
        // Repeating section (1 per submesh)
        // uint indexCount;
        // bool indexes32Bit
        // ushort* faceIndexes;  (indexCount)
        // OR
        // uint* faceIndexes;  (indexCount)
        M_MESH_BOUNDS = 0x9000,
        // float minx, miny, minz
        // float maxx, maxy, maxz
        // float radius

        // Added By DrEvil
        // optional chunk that contains a table of submesh indexes and the names of
        // the sub-meshes.
        M_SUBMESH_NAME_TABLE = 0xA000,
        // Subchunks of the name table. Each chunk contains an index & string
        M_SUBMESH_NAME_TABLE_ELEMENT = 0xA100,
        // short index
        // char* name

        // Optional chunk which stores precomputed edge data					 
        M_EDGE_LISTS = 0xB000,
        // Each LOD has a separate edge list
        M_EDGE_LIST_LOD = 0xB100,
        // ushort lodIndex
        // bool isManual			// If manual, no edge data here, loaded from manual mesh
        // bool isClosed
        // ulong numTriangles
        // ulong numEdgeGroups
        // Triangle* triangleList
        // ulong indexSet
        // ulong vertexSet
        // ulong vertIndex[3]
        // ulong sharedVertIndex[3] 
        // float normal[4] 

        M_EDGE_GROUP = 0xB110,
        // ulong vertexSet
        // ulong triStart
        // ulong triCount
        // ulong numEdges
        // Edge* edgeList
        // ulong  triIndex[2]
        // ulong  vertIndex[2]
        // ulong  sharedVertIndex[2]
        // bool degenerate

        // Optional poses section, referred to by pose keyframes
        M_POSES = 0xC000,
        M_POSE = 0xC100,
        // char* name (may be blank)
        // ushort target	// 0 for shared geometry, 
        // 1+ for submesh index + 1
        M_POSE_VERTEX = 0xC111,
        // ulong vertexIndex
        // float xoffset, yoffset, zoffset
        // Optional vertex animation chunk
        M_ANIMATIONS = 0xD000,
        M_ANIMATION = 0xD100,
        // char* name
        // float length
        M_ANIMATION_TRACK = 0xD110,
        // ushort type			// 1 == morph, 2 == pose
        // ushort target		// 0 for shared geometry, 
        // 1+ for submesh index + 1
        M_ANIMATION_MORPH_KEYFRAME = 0xD111,
        // float time
        // float x,y,z			// repeat by number of vertices in original geometry
        M_ANIMATION_POSE_KEYFRAME = 0xD112,
        // float time
        M_ANIMATION_POSE_REF = 0xD113, // repeat for number of referenced poses
        // ushort poseIndex 
        // float influence

        // Optional submesh extreme vertex list chink
        M_TABLE_EXTREMES = 0xE000,
        // ushort submesh_index;
        // float extremes [n_extremes][3];

        /* Version 1.2 of the .mesh format (deprecated)
        enum MeshChunkID {
            M_HEADER                = 0x1000,
                // char*          version           : Version number check
            M_MESH                = 0x3000,
                // bool skeletallyAnimated   // important flag which affects h/w buffer policies
                // Optional M_GEOMETRY chunk
                M_SUBMESH             = 0x4000, 
                    // char* materialName
                    // bool useSharedVertices
                    // uint indexCount
                    // bool indexes32Bit
                    // uint* faceVertexIndices (indexCount)
                    // OR
                    // ushort* faceVertexIndices (indexCount)
                    // M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
                    M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing
                        // ushort operationType
                    M_SUBMESH_BONE_ASSIGNMENT = 0x4100,
                        // Optional bone weights (repeating section)
                        // uint vertexIndex;
                        // ushort boneIndex;
                        // float weight;
                M_GEOMETRY          = 0x5000, // NB this chunk is embedded within M_MESH and M_SUBMESH
                */
        // uint vertexCount
        // float* pVertices (x, y, z order x numVertices)
        M_GEOMETRY_NORMALS = 0x5100,    //(Optional)
        // float* pNormals (x, y, z order x numVertices)
        M_GEOMETRY_COLOURS = 0x5200,    //(Optional)
        // ulong* pColours (RGBA 8888 format x numVertices)
        M_GEOMETRY_TEXCOORDS = 0x5300,    //(Optional, REPEATABLE, each one adds an extra set)
        // ushort dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
        // float* pTexCoords  (u [v] [w] order, dimensions x numVertices)
        /*
        M_MESH_SKELETON_LINK = 0x6000,
            // Optional link to skeleton
            // char* skeletonName           : name of .skeleton to use
        M_MESH_BONE_ASSIGNMENT = 0x7000,
            // Optional bone weights (repeating section)
            // uint vertexIndex;
            // ushort boneIndex;
            // float weight;
        M_MESH_LOD = 0x8000,
            // Optional LOD information
            // ushort numLevels;
            // bool manual;  (true for manual alternate meshes, false for generated)
            M_MESH_LOD_USAGE = 0x8100,
            // Repeating section, ordered in increasing depth
            // NB LOD 0 (full detail from 0 depth) is omitted
            // float fromSquaredDepth;
                M_MESH_LOD_MANUAL = 0x8110,
                // Required if M_MESH_LOD section manual = true
                // String manualMeshName;
                M_MESH_LOD_GENERATED = 0x8120,
                // Required if M_MESH_LOD section manual = false
                // Repeating section (1 per submesh)
                // uint indexCount;
                // bool indexes32Bit
                // ushort* faceIndexes;  (indexCount)
                // OR
                // uint* faceIndexes;  (indexCount)
        M_MESH_BOUNDS = 0x9000
            // float minx, miny, minz
            // float maxx, maxy, maxz
            // float radius

        // Added By DrEvil
        // optional chunk that contains a table of submesh indexes and the names of
        // the sub-meshes.
        M_SUBMESH_NAME_TABLE,
            // Subchunks of the name table. Each chunk contains an index & string
            M_SUBMESH_NAME_TABLE_ELEMENT,
                // short index
                // char* name

*/
    };

    /// Vertex element semantics, used to identify the meaning of vertex buffer contents
    enum VertexElementSemantic
    {
        /// Position, 3 reals per vertex
        VES_POSITION = 1,
        /// Blending weights
        VES_BLEND_WEIGHTS = 2,
        /// Blending indices
        VES_BLEND_INDICES = 3,
        /// Normal, 3 reals per vertex
        VES_NORMAL = 4,
        /// Diffuse colours
        VES_DIFFUSE = 5,
        /// Specular colours
        VES_SPECULAR = 6,
        /// Texture coordinates
        VES_TEXTURE_COORDINATES = 7,
        /// Binormal (Y axis if normal is Z)
        VES_BINORMAL = 8,
        /// Tangent (X axis if normal is Z)
        VES_TANGENT = 9

    };

    /// Vertex element type, used to identify the base types of the vertex contents
    enum VertexElementType
    {
        VET_FLOAT1 = 0,
        VET_FLOAT2 = 1,
        VET_FLOAT3 = 2,
        VET_FLOAT4 = 3,
        /// alias to more specific colour type - use the current rendersystem's colour packing
        VET_COLOUR = 4,
        VET_SHORT1 = 5,
        VET_SHORT2 = 6,
        VET_SHORT3 = 7,
        VET_SHORT4 = 8,
        VET_UBYTE4 = 9,
        /// D3D style compact colour
        VET_COLOUR_ARGB = 10,
        /// GL style compact colour
        VET_COLOUR_ABGR = 11
    };

    public class OgreMeshSerializerImpl : OgreSerializer
    {
        public OgreMeshSerializerImpl()
        {
            mVersion = "[MeshSerializer_v1.41]";
        }

        public void ImportMesh(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            //读取文件头
            UInt16 dest = reader.ReadUInt16();           

            //读取版本信息
            string ver = ReadString(reader);
#if DEBUG
            reader.BaseStream.Position = 25;
#endif
            MeshChunkID streamID;
            while (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                switch (streamID)
                {
                    case MeshChunkID.M_MESH:
                        readMesh(reader, mesh);
                        break;
                }
            }
        }

        //---------------------------------------------------------------------
        protected virtual void readMesh(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            MeshChunkID streamID;

            // bool skeletallyAnimated
            bool skeletallyAnimated;
            ReadBools(reader, out skeletallyAnimated, 1);

            // Find all substreams
            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                (streamID == MeshChunkID.M_GEOMETRY ||
                 streamID == MeshChunkID.M_SUBMESH ||
                 streamID == MeshChunkID.M_MESH_SKELETON_LINK ||
                 streamID == MeshChunkID.M_MESH_BONE_ASSIGNMENT ||
                 streamID == MeshChunkID.M_MESH_LOD ||
                 streamID == MeshChunkID.M_MESH_BOUNDS ||
                 streamID == MeshChunkID.M_SUBMESH_NAME_TABLE ||
                 streamID == MeshChunkID.M_EDGE_LISTS ||
                 streamID == MeshChunkID.M_POSES ||
                 streamID == MeshChunkID.M_ANIMATIONS ||
                 streamID == MeshChunkID.M_TABLE_EXTREMES))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_GEOMETRY:
                            try
                            {
                                mesh.HasSharedVertex = true;
                                readGeometry(reader, mesh, ref mesh.VertexData);
                            }
                            catch (Exception e)
                            {
                                mesh.HasSharedVertex = false;
                                //if (e.getNumber() == Exception::ERR_ITEM_NOT_FOUND)
                                //{
                                //    // duff geometry data entry with 0 vertices
                                //    //OGRE_DELETE pMesh->sharedVertexData;
                                //    //pMesh->sharedVertexData = 0;
                                //    // Skip this stream (pointer will have been returned to just after header)
                                //    //stream->skip(mCurrentstreamLen - STREAM_OVERHEAD_SIZE);
                                //    reader.BaseStream.Seek(mCurrentstreamLen - STREAM_OVERHEAD_SIZE, SeekOrigin.Current);
                                //}
                                //else
                                //{
                                //    throw;
                                //}
                            }
                            break;
                        case MeshChunkID.M_SUBMESH:
                            readSubMesh(reader, mesh);
                            break;
                        case MeshChunkID.M_MESH_SKELETON_LINK:
                            readSkeletonLink(reader, mesh);
                            break;
                        case MeshChunkID.M_MESH_BONE_ASSIGNMENT:
                            readMeshBoneAssignment(reader, mesh);
                            break;
                        case MeshChunkID.M_MESH_LOD:
                            readMeshLodInfo(reader, mesh);
                            break;
                        case MeshChunkID.M_MESH_BOUNDS:
                            readBoundsInfo(reader, mesh);
                            break;
                        case MeshChunkID.M_SUBMESH_NAME_TABLE:
                            readSubMeshNameTable(reader, mesh);
                            break;
                        case MeshChunkID.M_EDGE_LISTS:
                            readEdgeList(reader, mesh);
                            break;
                        case MeshChunkID.M_POSES:
                            readPoses(reader, mesh);
                            break;
                        case MeshChunkID.M_ANIMATIONS:
                            readAnimations(reader, mesh);
                            break;
                        case MeshChunkID.M_TABLE_EXTREMES:
                            readExtremes(reader, mesh);
                            break;
                    }

                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }

                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }
        }
        //---------------------------------------------------------------------
        protected virtual void readSubMesh(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            MeshChunkID streamID;
            OgreSubMesh subMesh = new OgreSubMesh();
            mesh.SubMeshes.Add(subMesh);

            // char* materialName
            String materialName = ReadString(reader);
            subMesh.MaterialName = materialName;

            // bool useSharedVertices
            bool useSharedVertices;
            ReadBools(reader,out useSharedVertices, 1);
            subMesh.UseSharedVertex = useSharedVertices;

            uint indexCount = 0;
            ReadInts(reader,out indexCount, 1);

            // bool indexes32Bit
            bool idx32bit;
            ReadBools(reader,out idx32bit, 1);
            if (indexCount > 0)
            {
                if (idx32bit)
                {
                    List<uint> ids = new List<uint>();
                    ReadInts(reader,out ids, (int)indexCount);
                    foreach (uint id in ids)
                    {
                        subMesh.IndicieList.Add((int)id);
                    }
                }
                else // 16-bit
                {
                    List<ushort> ids = new List<ushort>();
                    ReadShorts(reader,out ids, (int)indexCount);
                    foreach (ushort id in ids)
                    {
                        subMesh.IndicieList.Add((int)id);
                    }
                }
            }

            // M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
            //if (!sm->useSharedVertices)
            if (!useSharedVertices)
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                if (streamID != MeshChunkID.M_GEOMETRY)
                {
                    //OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Missing geometry data in mesh file",
                    //    "readSubMesh");
                }
                readGeometry(reader, mesh, ref subMesh.VertexData);
            }


            // Find all bone assignments, submesh operation, and texture aliases (if present)
            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    (streamID == MeshChunkID.M_SUBMESH_BONE_ASSIGNMENT ||
                     streamID == MeshChunkID.M_SUBMESH_OPERATION ||
                     streamID == MeshChunkID.M_SUBMESH_TEXTURE_ALIAS))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_SUBMESH_OPERATION:
                            readSubMeshOperation(reader, mesh, subMesh);
                            break;
                        case MeshChunkID.M_SUBMESH_BONE_ASSIGNMENT:
                            readSubMeshBoneAssignment(reader, mesh, subMesh);
                            break;
                        case MeshChunkID.M_SUBMESH_TEXTURE_ALIAS:
                            readSubMeshTextureAlias(reader, mesh, subMesh);
                            break;
                    }

                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }


        }
        //---------------------------------------------------------------------
        protected virtual void readGeometry(System.IO.BinaryReader reader, OgreMesh mesh, ref OgreVertexData vertexData)
        {
            uint vertexCount = 0;
            ReadInts(reader,out vertexCount, 1);
            vertexData.VertexCount = (int)vertexCount;

            // Find optional geometry streams
            if (!IsEof(reader))
            {
                MeshChunkID streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    (streamID == MeshChunkID.M_GEOMETRY_VERTEX_DECLARATION ||
                     streamID == MeshChunkID.M_GEOMETRY_VERTEX_BUFFER))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_GEOMETRY_VERTEX_DECLARATION:
                            readGeometryVertexDeclaration(reader, mesh, vertexData);
                            break;
                        case MeshChunkID.M_GEOMETRY_VERTEX_BUFFER:
                            readGeometryVertexBuffer(reader, mesh, vertexData);
                            break;
                    }
                    // Get next stream
                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }
                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }

            //// Perform any necessary colour conversion for an active rendersystem
            //if (Root::getSingletonPtr() && Root::getSingleton().getRenderSystem())
            //{
            //    // We don't know the source type if it's VET_COLOUR, but assume ARGB
            //    // since that's the most common. Won't get used unless the mesh is
            //    // ambiguous anyway, which will have been warned about in the log
            //    dest->convertPackedColour(VET_COLOUR_ARGB, 
            //        VertexElement::getBestColourVertexElementType());
            //}
        }
        //---------------------------------------------------------------------
        protected virtual void readGeometryVertexDeclaration(System.IO.BinaryReader reader, OgreMesh mesh, OgreVertexData vertexData)
        {
            //VertexData
            // Find optional geometry streams
            if (!IsEof(reader))
            {
                MeshChunkID streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    (streamID == MeshChunkID.M_GEOMETRY_VERTEX_ELEMENT))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_GEOMETRY_VERTEX_ELEMENT:
                            readGeometryVertexElement(reader, mesh, vertexData);
                            break;
                    }
                    // Get next stream
                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }
                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }

        }
        //---------------------------------------------------------------------
        protected virtual void readGeometryVertexElement(System.IO.BinaryReader reader, OgreMesh mesh, OgreVertexData vertexData)
        {
            ushort source, offset, index, tmp;
            VertexElementFormat format;
            VertexElementUsage usage;
            // ushort source;  	// buffer bind source
            ReadShorts(reader,out source, 1);
            // ushort type;    	// VertexElementType
            ReadShorts(reader,out tmp, 1);
            format = getVertexElementFormat(tmp);
            // ushort semantic; // VertexElementSemantic
            ReadShorts(reader,out tmp, 1);
            usage = getVertexElementUsage(tmp);
            // ushort offset;	// start offset in buffer in bytes
            ReadShorts(reader,out offset, 1);
            // ushort index;	// index of the semantic
            ReadShorts(reader,out index, 1);

            VertexElement vertexElement = new VertexElement(
                (short)source, (short)offset, format,
                VertexElementMethod.Default, usage, (byte)index);
            vertexData.VertexElements.Add(vertexElement);
            if (format == VertexElementFormat.Color)
            {
                LogManager.Instance.LogMessage(
                    "Warning: VET_COLOUR element type is deprecated, you should use " +
                    "one of the more specific types to indicate the byte order. " +
                    "Use OgreMeshUpgrade on " + mesh.Name + " as soon as possible. ");
            }

        }
        //---------------------------------------------------------------------
        protected virtual void readGeometryVertexBuffer(System.IO.BinaryReader reader, OgreMesh mesh, OgreVertexData vertexData)
        {
            ushort bindIndex, vertexSize;
            // ushort bindIndex;	// Index to bind this buffer to
            ReadShorts(reader,out bindIndex, 1);
            // ushort vertexSize;	// Per-vertex size, must agree with declaration at this index
            ReadShorts(reader,out vertexSize, 1);

            // Check for vertex data header
            MeshChunkID headerID;
            headerID = ReadChunk<MeshChunkID>(reader);
            if (headerID != MeshChunkID.M_GEOMETRY_VERTEX_BUFFER_DATA)
            {
                throw (GameViewerExceptionFactory.Create(ExceptionCodes.ERR_ITEM_NOT_FOUND, "Can't find vertex buffer data area",
                   "readGeometryVertexBuffer"));
            }
            byte[] bytes = reader.ReadBytes(vertexSize * vertexData.VertexCount);
            for (int i = 0; i < vertexData.VertexCount; i++)
            {
                VertexPositionNormalTexture vp = new VertexPositionNormalTexture();              
                for (int j = 0; j < vertexData.VertexElements.Count; j++)
                {
                    VertexElement ve = vertexData.VertexElements[j];
                    int offset = ve.Offset + i * vertexSize;
                    switch (ve.VertexElementUsage)
                    {
                        case VertexElementUsage.Position:
                            Vector3 pos = new Vector3(
                                ReadFloat(bytes, offset),
                                ReadFloat(bytes, offset + 4),
                                ReadFloat(bytes, offset + 8));
                            vp.Position = pos;
                            break;

                        case VertexElementUsage.Normal:
                            Vector3 normal = new Vector3(
                                ReadFloat(bytes, offset),
                                ReadFloat(bytes, offset + 4),
                                ReadFloat(bytes, offset + 8));
                            vp.Normal = normal;
                            break;

                        case VertexElementUsage.TextureCoordinate:
                            Vector2 uv = new Vector2(
                                ReadFloat(bytes, offset),
                                ReadFloat(bytes, offset + 4));
                            vp.TextureCoordinate = uv;
                            break;

                        case VertexElementUsage.Color:
                            break;
                    }
                }
                vertexData.VertexList.Add(vp);
            }

        }
        //---------------------------------------------------------------------
        protected virtual void readMeshBoneAssignment(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            //VertexBoneAssignment assign;

            // unsigned int vertexIndex;
            uint vertexIndex;
            ReadInts(reader,out vertexIndex, 1);
            // ushort boneIndex;
            ushort boneIndex;
            ReadShorts(reader,out boneIndex, 1);
            // float weight;
            float weight;
            ReadFloats(reader,out weight, 1);

            //pMesh->addBoneAssignment(assign);

        }
        //---------------------------------------------------------------------
        protected virtual void readSubMeshBoneAssignment(System.IO.BinaryReader reader, OgreMesh mesh, OgreSubMesh subMesh)
        {
            //VertexBoneAssignment assign;

            // unsigned int vertexIndex;
            uint vertexIndex;
            ReadInts(reader,out vertexIndex, 1);
            // ushort boneIndex;
            ushort boneIndex;
            ReadShorts(reader,out boneIndex, 1);
            // float weight;
            float weight;
            ReadFloats(reader,out weight, 1);

            //sub->addBoneAssignment(assign);

        }
        //---------------------------------------------------------------------
        protected virtual void readSubMeshOperation(System.IO.BinaryReader reader, OgreMesh mesh, OgreSubMesh subMesh)
        {
            // ushort operationType
            ushort opType;
            ReadShorts(reader,out opType, 1);
            //sm->operationType = static_cast<RenderOperation::OperationType>(opType);
        }
        //---------------------------------------------------------------------
        protected virtual void readSubMeshTextureAlias(System.IO.BinaryReader reader, OgreMesh mesh, OgreSubMesh subMesh)
        {
            String aliasName = ReadString(reader);
            String textureName = ReadString(reader);
            //sub->addTextureAlias(aliasName, textureName);
        }
        //---------------------------------------------------------------------
        protected virtual void readSkeletonLink(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            String skelName = ReadString(reader);
            //if(listener)
            //    listener->processSkeletonName(pMesh, out skelName);                
            mesh.SkeletonLink = skelName;
        }
        //---------------------------------------------------------------------
        protected virtual void readMeshLodInfo(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            MeshChunkID streamID;
            ushort i;

            // Read the strategy to be used for this mesh
            String strategyName = ReadString(reader);
            //LodStrategy *strategy = LodStrategyManager::getSingleton().getStrategy(strategyName);
            //pMesh->setLodStrategy(strategy);

            // ushort numLevels;
            ReadShorts(reader,out mesh.NumLods, 1);
            // bool manual;  (true for manual alternate meshes, false for generated)
            bool mIsLodManual;
            ReadBools(reader,out mIsLodManual, 1);

            /*
            // Preallocate submesh lod face data if not manual
            if (!pMesh->mIsLodManual)
            {
                ushort numsubs = pMesh->getNumSubMeshes();
                for (i = 0; i < numsubs; ++i)
                {
                    SubMesh* sm = pMesh->getSubMesh(i);
                    sm->mLodFaceList.resize(pMesh->mNumLods-1);
                }
            }
            */

            // Loop from 1 rather than 0 (full detail index is not in file)
            for (i = 1; i < mesh.NumLods; ++i)
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                if (streamID != MeshChunkID.M_MESH_LOD_USAGE)
                {
                    //OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
                    //    "Missing M_MESH_LOD_USAGE stream in " + pMesh->getName(),
                    //    "readMeshLodInfo");
                }
                // Read depth
                //MeshLodUsage usage;
                float userValue;
                ReadFloats(reader,out userValue, 1);

                if (mIsLodManual)
                {
                    readMeshLodUsageManual(reader, mesh, i);//, usage);
                }
                else //(!pMesh->isLodManual)
                {
                    readMeshLodUsageGenerated(reader, mesh, i);//, usage);
                }
                //usage.edgeData = NULL;

                // Save usage
                //pMesh->mMeshLodUsageList.push_back(usage);
            }


        }
        //---------------------------------------------------------------------
        protected virtual void readSubMeshNameTable(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            // The map for
            Dictionary<ushort, string> subMeshNames = new Dictionary<ushort, string>();
            MeshChunkID streamID;
            ushort subMeshIndex;

            // Need something to store the index, and the objects name
            // This table is a method that imported meshes can retain their naming
            // so that the names established in the modelling software can be used
            // to get the sub-meshes by name. The exporter must support exporting
            // the optional stream M_SUBMESH_NAME_TABLE.

            // Read in all the sub-streams. Each sub-stream should contain an index and Ogre::String for the name.
            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) && (streamID == MeshChunkID.M_SUBMESH_NAME_TABLE_ELEMENT))
                {
                    // Read in the index of the submesh.
                    ReadShorts(reader,out subMeshIndex, 1);
                    // Read in the String and map it to its index.
                    subMeshNames[subMeshIndex] = ReadString(reader);

                    // If we're not end of file get the next stream ID
                    if (!IsEof(reader))
                        streamID = ReadChunk<MeshChunkID>(reader);
                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }

            // Set all the submeshes names
            // ?

            //// Loop through and save out the index and names.
            //map<ushort, String>::type::const_iterator it = subMeshNames.begin();

            //while(it != subMeshNames.end())
            //{
            //    // Name this submesh to the stored name.
            //    pMesh->nameSubMesh(it->second, it->first);
            //    ++it;
            //}
        }
        //---------------------------------------------------------------------
        protected virtual void readEdgeList(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            MeshChunkID streamID;

            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    streamID == MeshChunkID.M_EDGE_LIST_LOD)
                {
                    // Process single LOD

                    // ushort lodIndex
                    ushort lodIndex;
                    ReadShorts(reader,out lodIndex, 1);

                    // bool isManual			// If manual, no edge data here, loaded from manual mesh
                    bool isManual;
                    ReadBools(reader,out isManual, 1);
                    // Only load in non-manual levels; others will be connected up by Mesh on demand
                    if (!isManual)
                    {

                        //MeshLodUsage& usage = const_cast<MeshLodUsage&>(pMesh->getLodLevel(lodIndex));

                        //usage.edgeData = OGRE_NEW EdgeData();

                        // Read detail information of the edge list
                        readEdgeListLodInfo(reader);//, usage.edgeData);
                        /*
                        // Postprocessing edge groups
                        EdgeData::EdgeGroupList::iterator egi, egend;
                        egend = usage.edgeData->edgeGroups.end();
                        for (egi = usage.edgeData->edgeGroups.begin(); egi != egend; ++egi)
                        {
                            EdgeData::EdgeGroup& edgeGroup = *egi;
                            // Populate edgeGroup.vertexData pointers
                            // If there is shared vertex data, vertexSet 0 is that,
                            // otherwise 0 is first dedicated
                            if (pMesh->sharedVertexData)
                            {
                                if (edgeGroup.vertexSet == 0)
                                {
                                    edgeGroup.vertexData = pMesh->sharedVertexData;
                                }
                                else
                                {
                                    edgeGroup.vertexData = pMesh->getSubMesh(
                                        (ushort)edgeGroup.vertexSet-1)->vertexData;
                                }
                            }
                            else
                            {
                                edgeGroup.vertexData = pMesh->getSubMesh(
                                    (ushort)edgeGroup.vertexSet)->vertexData;
                            }
                        }
                        */
                    }

                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }

            //pMesh->mEdgeListsBuilt = true;
        }
        //---------------------------------------------------------------------
        protected virtual void readEdgeListLodInfo(System.IO.BinaryReader reader)//        EdgeData* edgeData)
        {
            // bool isClosed
            bool isClosed;
            ReadBools(reader,out isClosed, 1);
            // unsigned long numTriangles
            UInt32 numTriangles;
            ReadInts(reader,out numTriangles, 1);
            // Allocate correct amount of memory
            //edgeData->triangles.resize(numTriangles);
            //edgeData->triangleFaceNormals.resize(numTriangles);
            //edgeData->triangleLightFacings.resize(numTriangles);
            // unsigned long numEdgeGroups
            UInt32 numEdgeGroups;
            ReadInts(reader,out numEdgeGroups, 1);
            // Allocate correct amount of memory
            //edgeData->edgeGroups.resize(numEdgeGroups);
            // Triangle* triangleList
            for (int t = 0; t < numTriangles; ++t)
            {
                //EdgeData::Triangle& tri = edgeData->triangles[t];
                uint indexSet;
                ReadInts(reader,out indexSet, 1);
                //tri.indexSet = tmp[0];
                uint vertexSet;
                ReadInts(reader,out vertexSet, 1);
                //tri.vertexSet = tmp[0];
                List<uint> vertIndex = new List<uint>();
                ReadInts(reader,out vertIndex, 3);
                //tri.vertIndex[0] = tmp[0];
                //tri.vertIndex[1] = tmp[1];
                //tri.vertIndex[2] = tmp[2];
                List<uint> sharedVertIndex = new List<uint>();
                ReadInts(reader,out sharedVertIndex, 3);
                //tri.sharedVertIndex[0] = tmp[0];
                //tri.sharedVertIndex[1] = tmp[1];
                //tri.sharedVertIndex[2] = tmp[2];
                List<float> normal = new List<float>();
                ReadFloats(reader,out normal /* &(edgeData->triangleFaceNormals[t].x)*/, 4);

            }

            for (UInt32 eg = 0; eg < numEdgeGroups; ++eg)
            {
                MeshChunkID streamID = ReadChunk<MeshChunkID>(reader);
                if (streamID != MeshChunkID.M_EDGE_GROUP)
                {
                    //OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                    //    "Missing M_EDGE_GROUP stream",
                    //    "MeshSerializerImpl::readEdgeListLodInfo");
                }
                //EdgeData::EdgeGroup& edgeGroup = edgeData->edgeGroups[eg];

                uint vertexSet;
                ReadInts(reader,out vertexSet, 1);
                //edgeGroup.vertexSet = tmp[0];
                uint triStart;
                ReadInts(reader,out triStart, 1);
                //edgeGroup.triStart = tmp[0];
                uint triCount;
                ReadInts(reader,out triCount, 1);
                //edgeGroup.triCount = tmp[0];
                // unsigned long numEdges
                uint numEdges;
                ReadInts(reader,out numEdges, 1);
                //edgeGroup.edges.resize(numEdges);
                // Edge* edgeList
                for (uint e = 0; e < numEdges; ++e)
                {
                    //EdgeData::Edge& edge = edgeGroup.edges[e];
                    List<uint> triIndex = new List<uint>();
                    ReadInts(reader,out triIndex, 2);
                    //edge.triIndex[0] = tmp[0];
                    //edge.triIndex[1] = tmp[1];
                    List<uint> vertIndex = new List<uint>();
                    ReadInts(reader,out vertIndex, 2);
                    //edge.vertIndex[0] = tmp[0];
                    //edge.vertIndex[1] = tmp[1];
                    List<uint> sharedVertIndex = new List<uint>();
                    ReadInts(reader,out sharedVertIndex, 2);
                    //edge.sharedVertIndex[0] = tmp[0];
                    //edge.sharedVertIndex[1] = tmp[1];
                    bool degenerate;
                    ReadBools(reader,out degenerate/* & (edge.degenerate)*/, 1);
                }
            }
        }
        //---------------------------------------------------------------------
        protected virtual void readPoses(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            MeshChunkID streamID;

            // Find all substreams
            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    (streamID == MeshChunkID.M_POSE))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_POSE:
                            readPose(reader, mesh);
                            break;

                    }

                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }
        }
        //---------------------------------------------------------------------
        protected virtual void readPose(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            // char* name (may be blank)
            String name = ReadString(reader);
            // ushort target
            ushort target;
            ReadShorts(reader,out target, 1);

            //Pose* pose = pMesh->createPose(target, name);

            // Find all substreams
            MeshChunkID streamID;
            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    (streamID == MeshChunkID.M_POSE_VERTEX))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_POSE_VERTEX:
                            // create vertex offset
                            UInt32 vertIndex;
                            Vector3 offset;
                            List<float> offsets = new List<float>();
                            // unsigned long vertexIndex
                            ReadInts(reader,out vertIndex, 1);
                            // float xoffset, yoffset, zoffset
                            ReadFloats(reader,out offsets, 3);

                            //pose->addVertex(vertIndex, offset);
                            break;

                    }

                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }

        }
        //---------------------------------------------------------------------
        protected virtual void readAnimations(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            MeshChunkID streamID;

            // Find all substreams
            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    (streamID == MeshChunkID.M_ANIMATION))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_ANIMATION:
                            readAnimation(reader, mesh);
                            break;

                    }

                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }


        }
        //---------------------------------------------------------------------
        protected virtual void readAnimation(System.IO.BinaryReader reader, OgreMesh mesh)
        {

            // char* name
            String name = ReadString(reader);
            // float length
            float len;
            ReadFloats(reader,out len, 1);

            //Animation* anim = pMesh->createAnimation(name, len);        
            AnimationContent anim = new AnimationContent();
            //mesh.Animations.Add(name, anim);

            // tracks
            MeshChunkID streamID;

            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    streamID == MeshChunkID.M_ANIMATION_TRACK)
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_ANIMATION_TRACK:
                            readAnimationTrack(reader, mesh, anim);
                            break;
                    };
                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }
        }
        //---------------------------------------------------------------------
        protected virtual void readAnimationTrack(System.IO.BinaryReader reader, OgreMesh mesh, AnimationContent animation)
        {
            // ushort type
            UInt16 inAnimType;
            ReadShorts(reader,out inAnimType, 1);
            //VertexAnimationType animType = (VertexAnimationType)inAnimType;

            // ushort target
            UInt16 target;
            ReadShorts(reader,out target, 1);

            //VertexAnimationTrack* track = anim->createVertexTrack(target,
            //	pMesh->getVertexDataByTrackHandle(target), animType);

            // keyframes
            MeshChunkID streamID;

            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    (streamID == MeshChunkID.M_ANIMATION_MORPH_KEYFRAME ||
                     streamID == MeshChunkID.M_ANIMATION_POSE_KEYFRAME))
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_ANIMATION_MORPH_KEYFRAME:
                            readMorphKeyFrame(reader);//, track);
                            break;
                        case MeshChunkID.M_ANIMATION_POSE_KEYFRAME:
                            readPoseKeyFrame(reader);//, track);
                            break;
                    };
                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }

        }
        //---------------------------------------------------------------------
        protected virtual void readMorphKeyFrame(System.IO.BinaryReader reader)//, VertexAnimationTrack* track)
        {
            // float time
            float timePos;
            ReadFloats(reader,out timePos, 1);

            //VertexMorphKeyFrame* kf = track->createVertexMorphKeyFrame(timePos);

            //// Create buffer, allow read and use shadow buffer
            //size_t vertexCount = track->getAssociatedVertexData()->vertexCount;
            //HardwareVertexBufferSharedPtr vbuf =
            //    HardwareBufferManager::getSingleton().createVertexBuffer(
            //        VertexElement::getTypeSize(VET_FLOAT3), vertexCount,
            //        HardwareBuffer::HBU_STATIC, true);
            //// float x,y,z			// repeat by number of vertices in original geometry
            int vertexCount = 1;
            List<float> pDst = new List<float>();
            //float* pDst = static_cast<float*>(
            //	vbuf->lock(HardwareBuffer::HBL_DISCARD));
            ReadFloats(reader,out pDst, vertexCount * 3);
            //vbuf->unlock();
            //kf->setVertexBuffer(vbuf);

        }
        //---------------------------------------------------------------------
        protected virtual void readPoseKeyFrame(System.IO.BinaryReader reader)//, VertexAnimationTrack* track)
        {
            // float time
            float timePos;
            ReadFloats(reader,out timePos, 1);

            // Create keyframe
            //VertexPoseKeyFrame* kf = track->createVertexPoseKeyFrame(timePos);

            MeshChunkID streamID;

            if (!IsEof(reader))
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                while (!IsEof(reader) &&
                    streamID == MeshChunkID.M_ANIMATION_POSE_REF)
                {
                    switch (streamID)
                    {
                        case MeshChunkID.M_ANIMATION_POSE_REF:
                            UInt16 poseIndex;
                            float influence;
                            // ushort poseIndex
                            ReadShorts(reader,out poseIndex, 1);
                            // float influence
                            ReadFloats(reader,out influence, 1);

                            //kf->addPoseReference(poseIndex, influence);

                            break;
                    };
                    if (!IsEof(reader))
                    {
                        streamID = ReadChunk<MeshChunkID>(reader);
                    }

                }
                if (!IsEof(reader))
                {
                    SkipChunk(reader);
                }
            }

        }
        //---------------------------------------------------------------------
        protected virtual void readExtremes(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            ushort idx;
            ReadShorts(reader,out idx, 1);

            OgreSubMesh subMesh = mesh.SubMeshes[idx];

            int n_floats = (int)(mCurrentstreamLen - STREAM_OVERHEAD_SIZE -
                            sizeof(ushort)) / sizeof(float);

            //assert ((n_floats % 3) == 0);

            //float *vert = OGRE_ALLOC_T(float, n_floats, MEMCATEGORY_GEOMETRY);
            List<float> vert = new List<float>();
            ReadFloats(reader,out vert, n_floats);

            //for (int i = 0; i < n_floats; i += 3)
            //	sm->extremityPoints.push_back(Vector3(vert [i], vert [i + 1], vert [i + 2]));

            //OGRE_FREE(vert, MEMCATEGORY_GEOMETRY);
        }
        //---------------------------------------------------------------------
        protected virtual void readBoundsInfo(System.IO.BinaryReader reader, OgreMesh mesh)
        {
            Vector3 min, max;
            // float minx, miny, minz
            ReadFloats(reader,out min.X, 1);
            ReadFloats(reader,out min.Y, 1);
            ReadFloats(reader,out min.Z, 1);
            // float maxx, maxy, maxz
            ReadFloats(reader,out max.X, 1);
            ReadFloats(reader,out max.Y, 1);
            ReadFloats(reader,out max.Z, 1);
            //AxisAlignedBox box(min, max);
            //pMesh->_setBounds(box, true);
            // float radius
            float radius;
            ReadFloats(reader,out radius, 1);
            //pMesh->_setBoundingSphereRadius(radius);
        }
        //---------------------------------------------------------------------
        protected virtual void readMeshLodUsageManual(System.IO.BinaryReader reader, OgreMesh mesh, ushort lodNum)//, MeshLodUsage& usage)
        {
            MeshChunkID streamID;
            // Read detail stream
            streamID = ReadChunk<MeshChunkID>(reader);
            if (streamID != MeshChunkID.M_MESH_LOD_MANUAL)
            {
                //OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
                //    "Missing M_MESH_LOD_MANUAL stream in " + pMesh->getName(),
                //    "MeshSerializerImpl::readMeshLodUsageManual");
            }

            string manualName = ReadString(reader);
            //usage.manualMesh.setNull(); // will trigger load later
        }
        //---------------------------------------------------------------------
        protected virtual void readMeshLodUsageGenerated(System.IO.BinaryReader reader, OgreMesh mesh, ushort lodNum)//, MeshLodUsage usage)
        {
            //usage.manualName = "";
            //usage.manualMesh.setNull();
            string manualName = "";

            // Get one set of detail per SubMesh
            ushort numSubs, i;
            MeshChunkID streamID;
            numSubs = (ushort)mesh.SubMeshes.Count;
            for (i = 0; i < numSubs; ++i)
            {
                streamID = ReadChunk<MeshChunkID>(reader);
                if (streamID != MeshChunkID.M_MESH_LOD_GENERATED)
                {
                    //OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
                    //    "Missing M_MESH_LOD_GENERATED stream in " + pMesh->getName(),
                    //    "MeshSerializerImpl::readMeshLodUsageGenerated");
                }

                //SubMesh* sm = pMesh->getSubMesh(i);
                // lodNum - 1 because SubMesh doesn't store full detail LOD
                //sm->mLodFaceList[lodNum - 1] = OGRE_NEW IndexData();
                //IndexData* indexData = sm->mLodFaceList[lodNum - 1];
                // unsigned int numIndexes
                uint numIndexes;
                ReadInts(reader,out numIndexes, 1);
                //indexData->indexCount = static_cast<size_t>(numIndexes);
                // bool indexes32Bit
                bool idx32Bit;
                ReadBools(reader,out idx32Bit, 1);
                // unsigned short*/int* faceIndexes;  ((v1, v2, v3) * numFaces)
                if (idx32Bit)
                {
                    //indexData->indexBuffer = HardwareBufferManager::getSingleton().
                    //    createIndexBuffer(HardwareIndexBuffer::IT_32BIT, indexData->indexCount,
                    //    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
                    //unsigned int* pIdx = static_cast<unsigned int*>(
                    //    indexData->indexBuffer->lock(
                    //        0,
                    //        indexData->indexBuffer->getSizeInBytes(),
                    //        HardwareBuffer::HBL_DISCARD) );
                    List<uint> pIdx = new List<uint>();
                    ReadInts(reader,out pIdx, (int)numIndexes);// indexData->indexCount);
                    //indexData->indexBuffer->unlock();

                }
                else
                {
                    //indexData->indexBuffer = HardwareBufferManager::getSingleton().
                    //    createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount,
                    //    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
                    //unsigned short* pIdx = static_cast<unsigned short*>(
                    //    indexData->indexBuffer->lock(
                    //        0,
                    //        indexData->indexBuffer->getSizeInBytes(),
                    //        HardwareBuffer::HBL_DISCARD) );
                    List<ushort> pIdx = new List<ushort>();
                    ReadShorts(reader,out pIdx, (int)numIndexes);//  indexData->indexCount);
                    //indexData->indexBuffer->unlock();

                }

            }
        }
        //---------------------------------------------------------------------
        protected VertexElementFormat getVertexElementFormat(ushort tmp)
        {
            VertexElementType vType = (VertexElementType)tmp;
            switch (vType)
            {
                case VertexElementType.VET_COLOUR:
                    return VertexElementFormat.Color;
                case VertexElementType.VET_COLOUR_ABGR: //?
                    return VertexElementFormat.Rgba32;
                case VertexElementType.VET_COLOUR_ARGB: //?
                    return VertexElementFormat.Rgba64;
                case VertexElementType.VET_FLOAT1:
                    return VertexElementFormat.Single;
                case VertexElementType.VET_FLOAT2:
                    return VertexElementFormat.Vector2;
                case VertexElementType.VET_FLOAT3:
                    return VertexElementFormat.Vector3;
                case VertexElementType.VET_FLOAT4:
                    return VertexElementFormat.Vector4;
                case VertexElementType.VET_SHORT1:
                    return VertexElementFormat.Rg32; //?
                case VertexElementType.VET_SHORT2:
                    return VertexElementFormat.Short2;
                case VertexElementType.VET_SHORT3:
                    return VertexElementFormat.Short4;//?
                case VertexElementType.VET_SHORT4:
                    return VertexElementFormat.Short4;
                case VertexElementType.VET_UBYTE4:
                    return VertexElementFormat.Byte4;
            }
            return VertexElementFormat.Vector4;
        }
        //---------------------------------------------------------------------
        protected VertexElementUsage getVertexElementUsage(ushort tmp)
        {
            VertexElementSemantic vSemantic = (VertexElementSemantic)tmp;
            switch (vSemantic)
            {
                case VertexElementSemantic.VES_BINORMAL:
                    return VertexElementUsage.Binormal;
                case VertexElementSemantic.VES_BLEND_INDICES:
                    return VertexElementUsage.BlendIndices;
                case VertexElementSemantic.VES_BLEND_WEIGHTS:
                    return VertexElementUsage.BlendWeight;
                case VertexElementSemantic.VES_DIFFUSE: //?
                    return VertexElementUsage.Color;
                case VertexElementSemantic.VES_NORMAL:
                    return VertexElementUsage.Normal;
                case VertexElementSemantic.VES_POSITION:
                    return VertexElementUsage.Position;
                case VertexElementSemantic.VES_SPECULAR: //?
                    return VertexElementUsage.Color;
                case VertexElementSemantic.VES_TANGENT:
                    return VertexElementUsage.Tangent;
                case VertexElementSemantic.VES_TEXTURE_COORDINATES:
                    return VertexElementUsage.TextureCoordinate;
            }
            return VertexElementUsage.Position;
        }

    }

    public class OgreMeshSerializerImpl_V1_4 : OgreMeshSerializerImpl
    {
        public OgreMeshSerializerImpl_V1_4()
        {
            mVersion = "[MeshSerializer_v1.40]";
        }
    }

    public class OgreMeshSerializerImpl_V1_3 : OgreMeshSerializerImpl
    {
        public OgreMeshSerializerImpl_V1_3()
        {
            mVersion = "[MeshSerializer_v1.30]";
        }
    }

    public class OgreMeshSerializerImpl_V1_2 : OgreMeshSerializerImpl_V1_3
    {
        public OgreMeshSerializerImpl_V1_2()
        {
            mVersion = "[MeshSerializer_v1.20]";
        }
    }

    public class OgreMeshSerializerImpl_V1_1 : OgreMeshSerializerImpl_V1_2
    {
        public OgreMeshSerializerImpl_V1_1()
        {
            mVersion = "[MeshSerializer_v1.10]";
        }
    }
}
